package gdut.imis.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import gdut.imis.Utils.Constants;
import gdut.imis.Utils.DateFormatUtil;
import gdut.imis.Utils.RedisCache;
import gdut.imis.Utils.Result;
import gdut.imis.domain.*;
import gdut.imis.enums.Status;
import gdut.imis.mapper.ManagerMapper;
import gdut.imis.mapper.UserMapper;
import gdut.imis.service.*;
import gdut.imis.vo.*;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @Description
 * @Author JiaFu
 * @Date 2023/4/8 19:27
 */
@Service
@RequiredArgsConstructor
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    private final ClassesService classesService;
    private final CourseService courseService;
    private final ClassCommitteeService classCommitteeService;
    private final CertificatesService certificatesService;
    private final ExamInfoService examInfoService;
    private final ClubInstitutionFileService clubInstitutionFileService;
    private final MatchesService matchesService;
    private final EmploymentFileService employmentFileService;
    private final PasswordEncoder passwordEncoder;
    private final UniversityService universityService;
    private final ManagerMapper managerMapper;
    private final RedisCache redisCache;
    private final ClassStudentRelService classStudentRelService;
    @Value("${env-file-path.base-path}")
    private String basePath;

    @Override
    public Result getUserInfo() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        UserLoginVo userLoginVo = (UserLoginVo) authentication.getPrincipal();
        if (Objects.isNull(userLoginVo)) {
            return Result.errorWithArgs(Status.FAILED, "用户未登录");
        }
        return Result.success(userLoginVo);
    }

    /***
     * 新增用户
     * @param: user
     * @return Result
     */
    @Override
    public Result addUser(User user) {
        boolean save = this.save(user);
        return Result.success();
    }

    /***
     * 获取用户详细信息，用于展示个人主页
     * @return Result
     */
    @Override
    public Result getUserDetails() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        UserLoginVo userLoginVo = (UserLoginVo) authentication.getPrincipal();
        if (userLoginVo.getIsManager()) {
            return Result.errorWithArgs(Status.FAILED, "非普通用户");
        }
        User user = userLoginVo.getUser();
        University university = universityService.getById(user.getUniversityId());
        UserVo userVo = new UserVo();
        BeanUtils.copyProperties(user, userVo);
        userVo.setUniversityName(university.getSchoolName());
        return Result.success(userVo);
    }

    /***
     * 更新用户基本信息
     * @param: user
     * @return Result
     */
    @Override
    public Result updateUserInfo(User user) {
        if (Objects.isNull(user)) {
            return Result.errorWithArgs(Status.REQUEST_PARAMS_NOT_VALID_ERROR, "user");
        }
        boolean flag = this.updateById(user);
        if (flag) {
            //数据库用户信息更新后redis存储的用户信息也要更新
            Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
            UserLoginVo userLoginVo = (UserLoginVo) authentication.getPrincipal();
            userLoginVo.setUser(user);
            redisCache.setCacheObject("login:" + user.getIdCard(), userLoginVo);
            return Result.success();
        }
        return Result.errorWithArgs(Status.FAILED, "更新用户信息失败");
    }

    /***
     * 用户修改密码（包括管理员，通用）
     * @param: originPassword
     * @param: newPassword
     * @return Result
     */
    @Override
    public Result updatePassword(String originPassword, String newPassword) {
        if (StringUtils.isNotBlank(originPassword) && StringUtils.isNotBlank(newPassword)) {
            Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
            UserLoginVo userLoginVo = (UserLoginVo) authentication.getPrincipal();
            String password = userLoginVo.getPassword();
            boolean flag = passwordEncoder.matches(originPassword, password);
            if (flag) {//初始密码正确，修改密码
                if (userLoginVo.getIsManager()) {//管理员修改密码
                    Manager manager = userLoginVo.getManager();
                    manager.setPassword(passwordEncoder.encode(newPassword));
                    int curFlag = managerMapper.updateById(manager);
                    if (curFlag != 0) {//修改成功，reidis信息也需要修改
                        userLoginVo.setManager(manager);
                        redisCache.setCacheObject("login:" + manager.getPhone(), userLoginVo);
                        return Result.success("修改成功，请重新登录", null);
                    }
                    return Result.errorWithArgs(Status.FAILED, "修改密码失败");
                } else {//普通用户修改密码
                    User user = userLoginVo.getUser();
                    user.setPassword(passwordEncoder.encode(newPassword));
                    boolean curFlag = this.updateById(user);
                    if (curFlag) {//修改成功，reidis信息也需要修改
                        userLoginVo.setUser(user);
                        redisCache.setCacheObject("login:" + user.getIdCard(), userLoginVo);
                        return Result.success("修改成功，请重新登录", null);
                    }
                    return Result.errorWithArgs(Status.FAILED, "修改密码失败");
                }
            }
            return Result.errorWithArgs(Status.FAILED, "初始密码不正确");
        }
        return Result.errorWithArgs(Status.REQUEST_PARAMS_NOT_VALID_ERROR, "originPassword/newPassword");
    }

    /***
     * 根据学校id查询该校老师
     * @param: universityId
     * @return Result
     */
    @Override
    public Result getTeacherListByUniversityId(Long universityId) {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper
                .eq(User::getUniversityId, universityId)
                .eq(User::getType, 1);
        List<User> userList = this.list(queryWrapper);
        if (CollectionUtils.isEmpty(userList)) {
            return Result.errorWithArgs(Status.FAILED, "没有查询到任何教师信息");
        }
        return Result.success(userList);
    }

    /***
     * 新增学生个人档案(要拥有users权限)
     * @param: userVo
     * @return Result
     */
    @Override
    @Transactional
    public Result addStudent(UserVo userVo) {
        if (Objects.isNull(userVo)) {
            return Result.errorWithArgs(Status.REQUEST_PARAMS_NOT_VALID_ERROR, "user");
        }
        //判断该身份证号是否已被使用
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getIdCard, userVo.getIdCard());
        User one = this.getOne(queryWrapper);
        if (one != null) {
            return Result.errorWithArgs(Status.FAILED, "该身份证号已被使用");
        }
        //默认头像url
        String avatarUrl = basePath + Constants.IMAGES + Constants.SEPARATOR + Constants.DEFAULT_PNG;
        //用户默认密码为身份证后六位
        String idCard = userVo.getIdCard();
        String password = idCard.substring(idCard.length() - 6);
        password = passwordEncoder.encode(password);
        userVo.setAvatarUrl(avatarUrl);
        userVo.setPassword(password);
        User user = new User();
        BeanUtils.copyProperties(userVo, user);
        boolean flag = this.save(user);
        if (flag) {
            ClassStudentRel classStudentRel = new ClassStudentRel();
            classStudentRel.setClassId(userVo.getClassId());
            classStudentRel.setStudentId(user.getId());
            boolean flag2 = classStudentRelService.save(classStudentRel);
            if (flag2) {
                return Result.success();
            }
            return Result.errorWithArgs(Status.FAILED, "新增学生档案失败");
        }
        throw new RuntimeException("新增学生档案失败");
    }

    /***
     * 通过学生id获取学生档案回忆录
     * @param: studentId
     * @return Result
     */
    @Override
    public Result getFileMemoryByStudentId(Long studentId) throws ParseException {
        ArrayList<FileMemoryVo> memoryList = new ArrayList<>();
        //获取班级档案回忆
        Result classesMemory = classesService.getClassesInfoByStuId(studentId);
        FileMemoryVo fileMemoryVo1 = classesMemoryToFileMemoryVo(classesMemory);
        //获取第一堂课档案回忆
        Result courseMemeory = courseService.getStudentFirstCourse(studentId);
        FileMemoryVo fileMemoryVo2 = courseMemoryToFileMemoryVo(courseMemeory);
        //获取班委档案回忆
        Result classCommitteMemory = classCommitteeService.getClassCommitteMemoryByStuId(studentId);
        FileMemoryVo fileMemoryVo3 = classCommitteMemoryToFileMemoryVo(classCommitteMemory);
        //证书档案回忆
        Result certificateMemory = certificatesService.getCertificateMemoryByStuId(studentId);
        FileMemoryVo fileMemoryVo4 = certificateMemoryToFileMemoryVo(certificateMemory);
        //第一次考试档案回忆
        Result examMemory = examInfoService.getExamMemoryBystuId(studentId);
        FileMemoryVo fileMemoryVo5 = examMemoryToFileMemoryVo(examMemory);
        //第一次加入社团档案回忆
        Result clubInstitutionMemory = clubInstitutionFileService.getClubInstitutionMemoryByStuId(studentId);
        FileMemoryVo fileMemoryVo6 = clubInstitutionMemoryToFileMemoryVo(clubInstitutionMemory);
        //第一次参加比赛档案回忆
        Result matchesMemory = matchesService.getMatchesMemoryByStuId(studentId);
        FileMemoryVo fileMemoryVo7 = matchesMemoryToFileMemoryVo(matchesMemory);
        //学生就业档案huiyi
        Result employmentMemory = employmentFileService.getEmploymentByStuId(studentId);
        FileMemoryVo fileMemoryVo8 = employmentMemoryToFileMemoryVo(employmentMemory);


        //将所有档案回忆加入回忆录
        if (fileMemoryVo1 != null) {
            memoryList.add(fileMemoryVo1);
        }
        if (fileMemoryVo2 != null) {
            memoryList.add(fileMemoryVo2);
        }
        if (fileMemoryVo3 != null) {
            memoryList.add(fileMemoryVo3);
        }
        if (fileMemoryVo4 != null) {
            memoryList.add(fileMemoryVo4);
        }
        if (fileMemoryVo5 != null) {
            memoryList.add(fileMemoryVo5);
        }
        if (fileMemoryVo6 != null) {
            memoryList.add(fileMemoryVo6);
        }
        if (fileMemoryVo7 != null) {
            memoryList.add(fileMemoryVo7);
        }
        if (fileMemoryVo8 != null) {
            memoryList.add(fileMemoryVo8);
        }

        //档案回忆录根据开始时间排序，从早到晚排序
        List<FileMemoryVo> resMemoryList = memoryList.stream().sorted((o1, o2) -> o1.getStart().compareTo(o2.getStart())).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(resMemoryList)) {
            return Result.errorWithArgs(Status.FAILED, "没有任何回忆");
        }
        //封装
        return Result.success(resMemoryList);
    }

    //将班级回忆录转换为档案回忆录统一格式
    private FileMemoryVo classesMemoryToFileMemoryVo(Result result) throws ParseException {
        if (result.getCode() != 0) {
            return null;
        }
        ClassesVo classesVo = (ClassesVo) result.getData();
        FileMemoryVo fileMemoryVo = new FileMemoryVo();
        fileMemoryVo.setStart(DateFormatUtil.LocalDateTimeToDate(classesVo.getCreateTime()));
        fileMemoryVo.setFileType("班级档案");
        StringBuilder strBuilder = new StringBuilder();
        strBuilder.append("在这一天，你来到了")
                .append(classesVo.getSchoolName())
                .append("，这所学校是一所")
                .append(classesVo.getSchoolType())
                .append("类型的大学，它坐落于")
                .append(classesVo.getSchoolAddress())
                .append("，你所在的班级是")
                .append(classesVo.getCollegeName())
                .append(classesVo.getGrade() + "级")
                .append(classesVo.getMajorName())
                .append(classesVo.getName())
                .append(",你的班主任是")
                .append(classesVo.getTeacherName())
                .append("。");
        fileMemoryVo.setContent1(strBuilder.toString());
        strBuilder.delete(0, strBuilder.length());
        strBuilder.append("在这里你将迎来了憧憬已久的大学生活，是否还记得踏入这所大学前的那种期待，想必这个班级一定给你留下了美好的回忆。");
        fileMemoryVo.setContent2(strBuilder.toString());
        return fileMemoryVo;
    }

    //将课程回忆录转换为档案回忆录统一格式
    private FileMemoryVo courseMemoryToFileMemoryVo(Result result) throws ParseException {
        if (result.getCode() != 0) {
            return null;
        }
        CourseVo courseVo = (CourseVo) result.getData();
        FileMemoryVo fileMemoryVo = new FileMemoryVo();
        fileMemoryVo.setStart(courseVo.getBeginTime());
        fileMemoryVo.setFileType("课程档案");
        StringBuilder strBuilder = new StringBuilder();
        strBuilder
                .append("在")
                .append(courseVo.getClassRoom())
                .append(courseVo.getLesson().getValue())
                .append("，你迎来了入学以来第一门课\"")
                .append(courseVo.getCourseName())
                .append("\"，这是一门")
                .append(courseVo.getCompulsory().getValue())
                .append("，你的授课老师是")
                .append(courseVo.getTeacherName())
                .append("。");
        fileMemoryVo.setContent1(strBuilder.toString());
        strBuilder.delete(0, strBuilder.length());
        strBuilder.append("是否还记得第一次上课的情景，是否还能想起")
                .append(courseVo.getTeacherName())
                .append("老师的面孔，大学时光过得真的很快，希望你回忆起这些都是温暖的。");
        fileMemoryVo.setContent2(strBuilder.toString());
        return fileMemoryVo;
    }

    //将班委回忆录转换为档案回忆录统一格式
    private FileMemoryVo classCommitteMemoryToFileMemoryVo(Result result) throws ParseException {
        if (result.getCode() != 0) {
            return null;
        }
        ClassCommitteeVo classCommitteeVo = (ClassCommitteeVo) result.getData();
        FileMemoryVo fileMemoryVo = new FileMemoryVo();
        fileMemoryVo.setStart(DateFormatUtil.LocalDateTimeToDate(classCommitteeVo.getCreateTime()));
        fileMemoryVo.setFileType("班委档案");
        StringBuilder strBuilder = new StringBuilder();
        strBuilder
                .append("通过班委竞选，在这天你成功被选为")
                .append(classCommitteeVo.getGrade())
                .append("级")
                .append(classCommitteeVo.getMajorName())
                .append(classCommitteeVo.getClassName())
                .append(classCommitteeVo.getPosition())
                .append("，这个职位的工作是")
                .append(classCommitteeVo.getRemark());
        fileMemoryVo.setContent1(strBuilder.toString());
        strBuilder.delete(0, strBuilder.length());
        strBuilder.append("你是个勇于挑战自我的学生，富有责任感，愿意牺牲自我为班集体服务，愿你在未来也能继续勇于承担重任，不断地突破自我。");
        fileMemoryVo.setContent2(strBuilder.toString());
        return fileMemoryVo;
    }

    //将班委回忆录转换为档案回忆录统一格式
    private FileMemoryVo certificateMemoryToFileMemoryVo(Result result) throws ParseException {
        if (result.getCode() != 0) {
            return null;
        }
        Certificates certificates = (Certificates) result.getData();
        FileMemoryVo fileMemoryVo = new FileMemoryVo();
        fileMemoryVo.setStart(certificates.getIssuedTime());
        fileMemoryVo.setFileType("证书档案");
        StringBuilder strBuilder = new StringBuilder();
        strBuilder
                .append("这是你首次参加大学的证书考试，恭喜你考取了")
                .append(certificates.getIssuedBy())
                .append("颁发的")
                .append(certificates.getCertName())
                .append("证书。");
        if (certificates.getGrade() != null) {
            strBuilder.append("你的成绩是")
                    .append(certificates.getGrade())
                    .append("分");
        }
        fileMemoryVo.setContent1(strBuilder.toString());
        strBuilder.delete(0, strBuilder.length());
        strBuilder.append("你为这场证书考试付出了很多的努力，但收获和努力是成正比的，希望你再接再厉，在以后取得更好的成绩");
        fileMemoryVo.setContent2(strBuilder.toString());
        return fileMemoryVo;
    }

    //将班委回忆录转换为档案回忆录统一格式
    private FileMemoryVo examMemoryToFileMemoryVo(Result result) throws ParseException {
        if (result.getCode() != 0) {
            return null;
        }
        ExamInfoVo examInfoVo = (ExamInfoVo) result.getData();
        FileMemoryVo fileMemoryVo = new FileMemoryVo();
        fileMemoryVo.setStart(DateFormatUtil.LocalDateTimeToDate(examInfoVo.getStartTime()));
        fileMemoryVo.setFileType("考试信息档案");
        StringBuilder strBuilder = new StringBuilder();
        strBuilder
                .append("这一天是你第一次参加大学的考试，你考试的科目是\"")
                .append(examInfoVo.getExamName())
                .append("\",在")
                .append(examInfoVo.getLocation())
                .append("由")
                .append(examInfoVo.getTeacherName())
                .append("老师监考，最终这门课程你考了")
                .append(examInfoVo.getGrade())
                .append("分，学分绩点为")
                .append(examInfoVo.getGradePoint())
                .append("。");
        fileMemoryVo.setContent1(strBuilder.toString());
        strBuilder.delete(0, strBuilder.length());
        strBuilder.append("不知道你是否还记得第一次参加这次考试是什么样的心情，是否会紧张，也许它对于你来说是一次难忘的经历。");
        fileMemoryVo.setContent2(strBuilder.toString());
        return fileMemoryVo;
    }

    //将社团机构回忆录转换为档案回忆录统一格式
    private FileMemoryVo clubInstitutionMemoryToFileMemoryVo(Result result) throws ParseException {
        if (result.getCode() != 0) {
            return null;
        }
        ClubInstitutionFileVo clubInstitutionFileVo = (ClubInstitutionFileVo) result.getData();
        FileMemoryVo fileMemoryVo = new FileMemoryVo();
        fileMemoryVo.setStart(DateFormatUtil.LocalDateTimeToDate(clubInstitutionFileVo.getCreateTime()));
        fileMemoryVo.setFileType("社团机构档案");
        StringBuilder strBuilder = new StringBuilder();
        strBuilder
                .append("今天你加入了")
                .append(clubInstitutionFileVo.getType().getValue())
                .append(clubInstitutionFileVo.getName())
                .append("，这是一个")
                .append(clubInstitutionFileVo.getIntroduction())
                .append("的一个")
                .append(clubInstitutionFileVo.getType().getValue())
                .append("，你所加入的部门是")
                .append(clubInstitutionFileVo.getDepartmentName())
                .append("，在这里主要工作是")
                .append(clubInstitutionFileVo.getDepartmentIntroduction())
                .append("。");
        fileMemoryVo.setContent1(strBuilder.toString());
        strBuilder.delete(0, strBuilder.length());
        strBuilder.append("这是你第一次加入学校的社团机构，也许你在这里交到了很多有趣可爱的朋友");
        fileMemoryVo.setContent2(strBuilder.toString());
        return fileMemoryVo;
    }

    //将第一次参加比赛回忆录转换为档案回忆录统一格式
    private FileMemoryVo matchesMemoryToFileMemoryVo(Result result) throws ParseException {
        if (result.getCode() != 0) {
            return null;
        }
        MatchesVo matchesVo = (MatchesVo) result.getData();
        FileMemoryVo fileMemoryVo = new FileMemoryVo();
        fileMemoryVo.setStart(DateFormatUtil.LocalDateTimeToDate(matchesVo.getCreateTime()));
        fileMemoryVo.setFileType("比赛档案");
        StringBuilder strBuilder = new StringBuilder();
        strBuilder
                .append("这一天，你获得了")
                .append(matchesVo.getName())
                .append(matchesVo.getPrize())
                .append("，这个比赛是由")
                .append(matchesVo.getOrganizer())
                .append("组织的，")
                .append(matchesVo.getIntroduction())
                .append("，你所在的团队是\"")
                .append(matchesVo.getTeamName())
                .append("\"，由")
                .append(matchesVo.getTeacherName())
                .append("老师指导。");
        fileMemoryVo.setContent1(strBuilder.toString());
        strBuilder.delete(0, strBuilder.length());
        strBuilder.append("这是一个很有意义的比赛，恭喜你取得了不错的成绩！");
        fileMemoryVo.setContent2(strBuilder.toString());
        return fileMemoryVo;
    }

    //将学生就业档案回忆录转换为档案回忆录统一格式
    private FileMemoryVo employmentMemoryToFileMemoryVo(Result result) throws ParseException {
        if (result.getCode() != 0) {
            return null;
        }
        EmploymentFile employmentFile = (EmploymentFile) result.getData();
        FileMemoryVo fileMemoryVo = new FileMemoryVo();
        fileMemoryVo.setStart(employmentFile.getEntryDate());
        fileMemoryVo.setFileType("就业档案");
        StringBuilder strBuilder = new StringBuilder();
        strBuilder
                .append("临近毕业，大家都纷纷找到符合自己的工作，你也不例外。你工作的公司是")
                .append(employmentFile.getCompanyName())
                .append("，坐落于")
                .append(employmentFile.getAddress())
                .append("，你的岗位是")
                .append(employmentFile.getPosition())
                .append("。");
        fileMemoryVo.setContent1(strBuilder.toString());
        strBuilder.delete(0, strBuilder.length());
        strBuilder.append("毕业后真的就步入社会了，祝愿你前程似锦，找到自己热爱的东西，从事着你喜欢的事业！");
        fileMemoryVo.setContent2(strBuilder.toString());
        return fileMemoryVo;
    }
}
